package compiles

import (
	"bytes"
	"context"
	"fmt"
	"math"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

type Measure struct{}

var Memery chan int = make(chan int, 2)
var timeLen chan int = make(chan int, 1)

//创建一个进程获取一个输出流
func (p *Measure) ExecProcess(ProcessPath string, Arge []string) JudgeRes {

	defer fmt.Println("执行完毕！")

	var JudgeRes JudgeRes = JudgeRes{}

	Cmd := exec.Command(ProcessPath, Arge...)

	var out bytes.Buffer
	Cmd.Stdout = &out

	ctx, canle := context.WithCancel(context.Background())

	ctx = context.WithValue(ctx, "time", nil)

	//对进程进行测量 保护
	Cmd.Start()

	pid := Cmd.Process.Pid

	go p.MeasureMeonery(ctx, pid)
	go p.outTimeMeasure(ctx, canle)

	Cmd.Wait()

	canle()

	JudgeRes.Locks.Lock()

	defer JudgeRes.Locks.Unlock()

	JudgeRes.MemoryCount = <-Memery

	JudgeRes.TimeCount = <-timeLen

	JudgeRes.Result = string(out.String())

	return JudgeRes
}

type ExecFunc func(ProcessPath string, Arge []string) JudgeRes

type OverTimeError struct {
}

func (o OverTimeError) Error() string {
	return "超时了！"
}

//解析出内存 从ps工具中
func GetRss(ctx context.Context, pid int) int {

	cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("ps -p %d -o rss", pid))
	bytes, _ := cmd.CombinedOutput()
	cmd.Wait()
	Rss := strings.ReplaceAll(string(bytes), "RSS", "")
	Rss = strings.Replace(Rss, "\n", "", -1)
	Rss = strings.Replace(Rss, " ", "", -1)
	Rss = strings.Replace(Rss, "0x00", "", -1)

	rss, err := strconv.Atoi(Rss)
	if err != nil {
		fmt.Printf(err.Error(), "\n")
	}

	return rss

}

func (p Measure) StopProcess(cmd exec.Cmd, ctx context.Context) {
	<-ctx.Done()
	cmd.Process.Kill() //关闭当前进程 当发现有超时 内存超出时
}

//进行超时检测
func (p Measure) outTimeMeasure(ctx context.Context, canle context.CancelFunc) {
	var StartTime time.Time = time.Now()

	for {
		select {
		case <-ctx.Done():
			fmt.Println("关闭了")
			timeLen <- int(time.Since(StartTime).Microseconds())
		default:
			//如何大于100 则定义为超时
			if int(time.Since(StartTime).Milliseconds()) > 100 {
				fmt.Println("超时了 ")
				timeLen <- 0
				canle()
			}
		}
	}
}

//测量内存
func (p Measure) MeasureMeonery(ctx context.Context, pid int) {

	var MemeryVal int = 1
	for {
		select {
		case <-ctx.Done():
			Memery <- MemeryVal
			return
		default:
			//获取时间差
			Rss := GetRss(ctx, pid)
			MemeryVal = int(math.Max(float64(Rss), float64(MemeryVal))) //获取最大内存

			if MemeryVal > 100000 {
				fmt.Println("内存溢出了 ")
				Memery <- MemeryVal
				return
			}

		}
	}

}
